#include <stdio.h>
#include <stddef.h>
#include <unistd.h>
#include "seqiot.h"
#include "value.h"
#include "model.h"
#include "sqlite.h"
#include "sysinfo.h"

seqiot_t *seqiot_new() {
    seqiot_t *seqiot = z_calloc(1, sizeof(seqiot_t));
    strcpy(seqiot->local_address, "127.0.0.1");
    return seqiot;
}

void seqiot_free(seqiot_t *seqiot) {
    if (!seqiot)return;

    vector_foreach(&seqiot->catalogs, (vector_foreach_callback) data_catalog_free);
    vector_clear(&seqiot->catalogs);

    vector_foreach(&seqiot->products, (vector_foreach_callback) product_free);
    vector_clear(&seqiot->products);

    vector_foreach(&seqiot->channels, (vector_foreach_callback) channel_free);
    vector_clear(&seqiot->channels);

    vector_foreach(&seqiot->sysinfos, (vector_foreach_callback) sys_info_free);
    vector_clear(&seqiot->sysinfos);

    z_free(seqiot);
}

int get_conf_file(char *filename, size_t size) {
    if (NULL == filename || size < 40) return -1;

    char hostname[32];
    int rc = gethostname(hostname, sizeof(hostname));
    if (rc < 0) return -1;

    sprintf(filename, "/etc/%s.db", hostname);

    return 0;
}

sqlite3 *open_conf_db(const char *filename) {
    if (NULL != filename) {
        return sqlite_open(filename);
    } else {
        char buf[NAME_MAX];
        if (get_conf_file(buf, sizeof(buf)) >= 0) {
            return sqlite_open(buf);
        }
    }

    return NULL;
}

sqlite3 *open_model_db(const char *filename) {
    if (NULL != filename) {
        return sqlite_open(filename);
    } else {
        return sqlite_open("/etc/thingmodel.db");
    }
}

void close_db(sqlite3 *db) {
    if (NULL != db) {
        sqlite3_close(db);
    }
}

static uplink_t _default_uplink = {
        .super.id = 0,
        .super.name = "default",
        .times = 1,
        .rtu = 1,
        .remote_address.addr = "a1LL8AZKUKw.iot-as-mqtt.cn-shanghai.aliyuncs.com",
        .remote_address.port = 443,
        .ssl = true,
        .timeout = 3,
        .heartbeat = 1,
        .product_key="a1LL8AZKUKw",
        .device_key = "00000000",
        .device_secret ="ju7bxqxyxISz1lHeRXIeWZT4vTViBU09",
};

void read_conf(sqlite3 *db, seqiot_t *seqiot, obj_id channel_id, obj_id uplink_id) {
    read_stmt_sys_infos(db, &seqiot->sysinfos);

    if (0 == uplink_id) {
        //如果channel_id=0，获取全部channel
        read_stmt_uplink(db, &seqiot->uplinks, uplink_id);
    } else {
        read_stmt_uplinks(db, &seqiot->uplinks);
    }
    if (vector_size(&seqiot->uplinks)) {
        seqiot->default_uplink = vector_get(&seqiot->uplinks, 0);
        seqiot->default_uplink->times = 1;
    } else {
        seqiot->default_uplink = &_default_uplink;
    }

    if (0 == channel_id) {
        //如果channel_id=0，获取全部channel
        read_stmt_channels(db, &seqiot->channels);
    } else {
        read_stmt_channel(db, &seqiot->channels, channel_id);
    }

    //迭代所有channel
    for (int i = 0; i < vector_size(&seqiot->channels); ++i) {
        channel_t *channel = vector_get(&seqiot->channels, i);
        //获取该channel下的所有device
        read_stmt_devices(db, &channel->devices, channel->super.id);
    }
}

void read_model(sqlite3 *db, seqiot_t *seqiot) {
    read_stmt_catalogs(db, &seqiot->catalogs);

    //获取所有product
    read_stmt_products(db, &seqiot->products);

    //需要加载物模型
    for (int i = 0; i < vector_size(&seqiot->channels); ++i) {
        channel_t *channel = vector_get(&seqiot->channels, i);
        for (int j = 0; j < vector_size(&channel->devices); ++j) {
            device_t *device = vector_get(&channel->devices, j);
            for (int k = 0; k < vector_size(&seqiot->products); ++k) {
                product_t *product = vector_get(&seqiot->products, k);
                if (device->product == product->super.id) {
                    //标记为需要加载
                    product->_loading = true;
                    //建立和product的链接关系
                    device->_product = product;
                    break;
                }
            }
        }
    }

    //加载被device使用的物模型
    for (int i = 0; i < vector_size(&seqiot->products); ++i) {
        product_t *product = vector_get(&seqiot->products, i);
        if (product->_loading && !product->_loaded) {
            product->_loaded = true;
            read_stmt_thing_models(db, product);
        }
    }
}

static int get_shift(product_t *product, segment_e segment) {
    switch (segment) {
        case seg_di:
            return product->di_shift;
        case seg_do :
            return product->do_shift;
        case seg_ai:
            return product->ai_shift;
        case seg_ao:
            return product->ao_shift;
        default:
            return 0;
    }
}

static product_t *clone_product(product_t *product, int dev_idx) {
    product_t *clone_product = product_new();

    memmove(clone_product, product, sizeof(*clone_product));
    bzero(clone_product->thing_model, sizeof(clone_product->thing_model));

    for (int i = 0; i < sizeof(clone_product->thing_model) / sizeof(clone_product->thing_model[0]); ++i) {
        vector_t *seg_list = &product->thing_model[i];

        vector_t *clone_seg_list = &clone_product->thing_model[i];
        clone_seg_list->capi = clone_seg_list->size = seg_list->size;
        clone_seg_list->vals = (void **) z_calloc(clone_seg_list->capi, sizeof(void *));

        int shift = get_shift(product, i);
        for (int j = 0; j < vector_size(seg_list); ++j) {
            thing_model_t *model = vector_get(seg_list, j);

            thing_model_t *clone_model = thing_model_new();
            memmove(clone_model, model, sizeof(*clone_model));

            clone_model->super.id = model->super.id;
            clone_model->offset = model->super.id + shift * dev_idx;

            clone_seg_list->vals[j] = clone_model;
        }
    }

    return clone_product;
}

//准备value所占用空间
void post_device_values(seqiot_t *seqiot) {
    for (int i = 0; i < vector_size(&seqiot->channels); ++i) {
        channel_t *channel = vector_get(&seqiot->channels, i);
        for (int j = 0; j < vector_size(&channel->devices); ++j) {
            device_t *device = vector_get(&channel->devices, j);
            device->_product = clone_product(device->_product, device->shift_idx);

            for (int k = 0; k < sizeof(device->_product->thing_model) / sizeof(device->_product->thing_model[0]); ++k) {
                vector_t *seg_list = &device->_product->thing_model[k];
                vector_t *val_list = &device->thing_value[k];
                for (int l = 0; l < vector_size(seg_list); ++l) {
                    vector_add(val_list, value_new());
                }
            }
        }
    }
}

/**读取配置文件*/
int read_config(seqiot_t *seqiot, const char *filename, obj_id channel_id, obj_id uplink_id) {
    sqlite3 *conf_db = open_conf_db(filename);
    if (NULL == conf_db) return -1;

    read_conf(conf_db, seqiot, channel_id, uplink_id);
    close_db(conf_db);

    sqlite3 *model_db = sqlite_open("/etc/thingmodel.db");
    if (NULL == model_db) return -1;

    read_model(model_db, seqiot);
    close_db(model_db);

    post_device_values(seqiot);

    return 0;
}
